use crate::config::{DataType, ByteOrder, PointConfig};
use crate::error::{Result, ModbusCollectorError};
use regex::Regex;
use std::sync::OnceLock;

/// 数据解析器
pub struct DataParser;

impl DataParser {
    /// 解析原始寄存器数据为工程值
    pub fn parse_data(registers: &[u16], point: &PointConfig) -> Result<f64> {
        // 首先根据数据类型和字节序解析原始值
        let raw_value = Self::parse_raw_value(registers, &point.data_type, &point.byte_order)?;
        
        // 然后应用操作表达式
        let result = if let Some(operation) = &point.operation {
            Self::apply_operation(raw_value, operation)?
        } else {
            raw_value
        };
        
        Ok(result)
    }
    
    /// 解析原始值
    fn parse_raw_value(registers: &[u16], data_type: &DataType, byte_order: &ByteOrder) -> Result<f64> {
        match data_type {
            DataType::Bool => {
                if registers.is_empty() {
                    return Err(ModbusCollectorError::Config("No data for bool parsing".to_string()));
                }
                Ok(if registers[0] != 0 { 1.0 } else { 0.0 })
            },
            DataType::Int16 => {
                if registers.is_empty() {
                    return Err(ModbusCollectorError::Config("No data for int16 parsing".to_string()));
                }
                Ok(registers[0] as i16 as f64)
            },
            DataType::UInt16 => {
                if registers.is_empty() {
                    return Err(ModbusCollectorError::Config("No data for uint16 parsing".to_string()));
                }
                Ok(registers[0] as f64)
            },
            DataType::Int32 => {
                if registers.len() < 2 {
                    return Err(ModbusCollectorError::Config("Insufficient data for int32 parsing".to_string()));
                }
                let value = Self::combine_registers_32(&registers[0..2], byte_order);
                Ok(value as i32 as f64)
            },
            DataType::UInt32 => {
                if registers.len() < 2 {
                    return Err(ModbusCollectorError::Config("Insufficient data for uint32 parsing".to_string()));
                }
                let value = Self::combine_registers_32(&registers[0..2], byte_order);
                Ok(value as f64)
            },
            DataType::Float32 => {
                if registers.len() < 2 {
                    return Err(ModbusCollectorError::Config("Insufficient data for float32 parsing".to_string()));
                }
                let value = Self::combine_registers_32(&registers[0..2], byte_order);
                let float_val = f32::from_bits(value);
                Ok(float_val as f64)
            },
            DataType::Float64 => {
                if registers.len() < 4 {
                    return Err(ModbusCollectorError::Config("Insufficient data for float64 parsing".to_string()));
                }
                let value = Self::combine_registers_64(&registers[0..4], byte_order);
                let float_val = f64::from_bits(value);
                Ok(float_val)
            },
        }
    }
    
    /// 组合两个寄存器为32位值
    fn combine_registers_32(registers: &[u16], byte_order: &ByteOrder) -> u32 {
        let reg0 = registers[0];
        let reg1 = registers[1];
        
        match byte_order {
            ByteOrder::Abcd => ((reg0 as u32) << 16) | (reg1 as u32),  // 大端
            ByteOrder::Dcba => ((reg1 as u32) << 16) | (reg0 as u32),  // 小端
            ByteOrder::Badc => {
                let byte0 = (reg0 & 0xFF) as u32;
                let byte1 = ((reg0 >> 8) & 0xFF) as u32;
                let byte2 = (reg1 & 0xFF) as u32;
                let byte3 = ((reg1 >> 8) & 0xFF) as u32;
                (byte1 << 24) | (byte0 << 16) | (byte3 << 8) | byte2
            },
            ByteOrder::Cdab => {
                let byte0 = (reg0 & 0xFF) as u32;
                let byte1 = ((reg0 >> 8) & 0xFF) as u32;
                let byte2 = (reg1 & 0xFF) as u32;
                let byte3 = ((reg1 >> 8) & 0xFF) as u32;
                (byte2 << 24) | (byte3 << 16) | (byte0 << 8) | byte1
            },
        }
    }
    
    /// 组合四个寄存器为64位值
    fn combine_registers_64(registers: &[u16], byte_order: &ByteOrder) -> u64 {
        match byte_order {
            ByteOrder::Abcd => {
                ((registers[0] as u64) << 48) | 
                ((registers[1] as u64) << 32) | 
                ((registers[2] as u64) << 16) | 
                (registers[3] as u64)
            },
            ByteOrder::Dcba => {
                ((registers[3] as u64) << 48) | 
                ((registers[2] as u64) << 32) | 
                ((registers[1] as u64) << 16) | 
                (registers[0] as u64)
            },
            ByteOrder::Badc => {
                // 实现字节交换逻辑
                let high32 = Self::combine_registers_32(&[registers[1], registers[0]], &ByteOrder::Abcd);
                let low32 = Self::combine_registers_32(&[registers[3], registers[2]], &ByteOrder::Abcd);
                ((high32 as u64) << 32) | (low32 as u64)
            },
            ByteOrder::Cdab => {
                // 实现字节对交换逻辑
                let high32 = Self::combine_registers_32(&[registers[0], registers[1]], &ByteOrder::Dcba);
                let low32 = Self::combine_registers_32(&[registers[2], registers[3]], &ByteOrder::Dcba);
                ((high32 as u64) << 32) | (low32 as u64)
            },
        }
    }
    
    /// 应用操作表达式
    fn apply_operation(value: f64, operation: &str) -> Result<f64> {
        static OPERATION_REGEX: OnceLock<Regex> = OnceLock::new();
        let regex = OPERATION_REGEX.get_or_init(|| {
            Regex::new(r"^([+\-*/])(\d+(?:\.\d+)?)$").unwrap()
        });
        
        // 支持简单的操作: +10, -5, *0.1, /100
        if let Some(captures) = regex.captures(operation.trim()) {
            let operator = &captures[1];
            let operand: f64 = captures[2].parse()
                .map_err(|_| ModbusCollectorError::Config(
                    format!("Invalid operand in operation: {}", operation)
                ))?;
            
            match operator {
                "+" => Ok(value + operand),
                "-" => Ok(value - operand),
                "*" => Ok(value * operand),
                "/" => {
                    if operand == 0.0 {
                        Err(ModbusCollectorError::Config("Division by zero in operation".to_string()))
                    } else {
                        Ok(value / operand)
                    }
                },
                _ => Err(ModbusCollectorError::Config(
                    format!("Unsupported operator: {}", operator)
                )),
            }
        } else {
            // 尝试解析复杂表达式 (如 x*2+10)
            Self::evaluate_expression(value, operation)
        }
    }
    
    /// 评估复杂表达式
    fn evaluate_expression(x: f64, expression: &str) -> Result<f64> {
        static EXPRESSION_REGEX: OnceLock<Regex> = OnceLock::new();
        let regex = EXPRESSION_REGEX.get_or_init(|| {
            Regex::new(r"x\s*([+\-*/])\s*(\d+(?:\.\d+)?)\s*([+\-*/])\s*(\d+(?:\.\d+)?)")
                .unwrap()
        });
        
        if let Some(captures) = regex.captures(expression.trim()) {
            let op1 = &captures[1];
            let val1: f64 = captures[2].parse()
                .map_err(|_| ModbusCollectorError::Config(
                    format!("Invalid value in expression: {}", expression)
                ))?;
            let op2 = &captures[3];
            let val2: f64 = captures[4].parse()
                .map_err(|_| ModbusCollectorError::Config(
                    format!("Invalid value in expression: {}", expression)
                ))?;
            
            // 计算第一个操作
            let intermediate = match op1 {
                "+" => x + val1,
                "-" => x - val1,
                "*" => x * val1,
                "/" => {
                    if val1 == 0.0 {
                        return Err(ModbusCollectorError::Config("Division by zero in expression".to_string()));
                    }
                    x / val1
                },
                _ => return Err(ModbusCollectorError::Config(
                    format!("Unsupported operator: {}", op1)
                )),
            };
            
            // 计算第二个操作
            let result = match op2 {
                "+" => intermediate + val2,
                "-" => intermediate - val2,
                "*" => intermediate * val2,
                "/" => {
                    if val2 == 0.0 {
                        return Err(ModbusCollectorError::Config("Division by zero in expression".to_string()));
                    }
                    intermediate / val2
                },
                _ => return Err(ModbusCollectorError::Config(
                    format!("Unsupported operator: {}", op2)
                )),
            };
            
            Ok(result)
        } else {
            // 简单的单操作表达式 (如 x*0.1)
            static SIMPLE_REGEX: OnceLock<Regex> = OnceLock::new();
            let simple_regex = SIMPLE_REGEX.get_or_init(|| {
                Regex::new(r"^x\s*([+\-*/])\s*(\d+(?:\.\d+)?)$").unwrap()
            });
            
            if let Some(captures) = simple_regex.captures(expression.trim()) {
                let operator = &captures[1];
                let operand: f64 = captures[2].parse()
                    .map_err(|_| ModbusCollectorError::Config(
                        format!("Invalid operand in expression: {}", expression)
                    ))?;
                
                match operator {
                    "+" => Ok(x + operand),
                    "-" => Ok(x - operand),
                    "*" => Ok(x * operand),
                    "/" => {
                        if operand == 0.0 {
                            Err(ModbusCollectorError::Config("Division by zero in expression".to_string()))
                        } else {
                            Ok(x / operand)
                        }
                    },
                    _ => Err(ModbusCollectorError::Config(
                        format!("Unsupported operator: {}", operator)
                    )),
                }
            } else {
                Err(ModbusCollectorError::Config(
                    format!("Invalid expression format: {}", expression)
                ))
            }
        }
    }
    
    /// 将工程值转换为原始寄存器值（用于写入）
    pub fn encode_data(value: f64, point: &PointConfig) -> Result<Vec<u16>> {
        match point.data_type {
            DataType::Bool => Ok(vec![if value != 0.0 { 1 } else { 0 }]),
            DataType::Int16 => Ok(vec![value as i16 as u16]),
            DataType::UInt16 => Ok(vec![value as u16]),
            DataType::Int32 => {
                let int_val = value as i32 as u32;
                Ok(Self::split_u32_to_registers(int_val, &point.byte_order))
            },
            DataType::UInt32 => {
                let uint_val = value as u32;
                Ok(Self::split_u32_to_registers(uint_val, &point.byte_order))
            },
            DataType::Float32 => {
                let float_val = value as f32;
                let bits = float_val.to_bits();
                Ok(Self::split_u32_to_registers(bits, &point.byte_order))
            },
            DataType::Float64 => {
                let bits = value.to_bits();
                Ok(Self::split_u64_to_registers(bits, &point.byte_order))
            },
        }
    }
    
    /// 将32位值拆分为寄存器
    fn split_u32_to_registers(value: u32, byte_order: &ByteOrder) -> Vec<u16> {
        match byte_order {
            ByteOrder::Abcd => vec![(value >> 16) as u16, value as u16],
            ByteOrder::Dcba => vec![value as u16, (value >> 16) as u16],
            ByteOrder::Badc => {
                let reg0 = ((value >> 16) & 0xFF) | (((value >> 24) & 0xFF) << 8);
                let reg1 = (value & 0xFF) | (((value >> 8) & 0xFF) << 8);
                vec![reg0 as u16, reg1 as u16]
            },
            ByteOrder::Cdab => {
                let reg0 = ((value >> 8) & 0xFF) | (((value >> 16) & 0xFF) << 8);
                let reg1 = ((value >> 24) & 0xFF) | ((value & 0xFF) << 8);
                vec![reg0 as u16, reg1 as u16]
            },
        }
    }
    
    /// 将64位值拆分为寄存器
    fn split_u64_to_registers(value: u64, byte_order: &ByteOrder) -> Vec<u16> {
        match byte_order {
            ByteOrder::Abcd => vec![
                (value >> 48) as u16,
                (value >> 32) as u16,
                (value >> 16) as u16,
                value as u16,
            ],
            ByteOrder::Dcba => vec![
                value as u16,
                (value >> 16) as u16,
                (value >> 32) as u16,
                (value >> 48) as u16,
            ],
            ByteOrder::Badc => {
                let high32 = (value >> 32) as u32;
                let low32 = value as u32;
                let mut result = Self::split_u32_to_registers(high32, &ByteOrder::Dcba);
                result.extend(Self::split_u32_to_registers(low32, &ByteOrder::Dcba));
                result
            },
            ByteOrder::Cdab => {
                let high32 = (value >> 32) as u32;
                let low32 = value as u32;
                let mut result = Self::split_u32_to_registers(high32, &ByteOrder::Badc);
                result.extend(Self::split_u32_to_registers(low32, &ByteOrder::Badc));
                result
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_simple_operations() {
        assert_eq!(DataParser::apply_operation(10.0, "*0.1").unwrap(), 1.0);
        assert_eq!(DataParser::apply_operation(100.0, "/10").unwrap(), 10.0);
        assert_eq!(DataParser::apply_operation(20.0, "+5").unwrap(), 25.0);
        assert_eq!(DataParser::apply_operation(30.0, "-10").unwrap(), 20.0);
    }
    
    #[test]
    fn test_complex_expressions() {
        assert_eq!(DataParser::evaluate_expression(10.0, "x*2+5").unwrap(), 25.0);
        assert_eq!(DataParser::evaluate_expression(100.0, "x/10-5").unwrap(), 5.0);
    }
    
    #[test]
    fn test_data_parsing() {
        use crate::config::{PointConfig, DataType, ByteOrder};
        
        let point = PointConfig {
            point_id: "test".to_string(),
            device_id: "test".to_string(),
            name: "test".to_string(),
            address: 40001,
            data_type: DataType::UInt16,
            operation: Some("*0.1".to_string()),
            byte_order: ByteOrder::Abcd,
            is_historical: false,
            is_monitored: false,
        };
        
        let result = DataParser::parse_data(&[1000], &point).unwrap();
        assert_eq!(result, 100.0);
    }
}